/*********************************************************/
/*
	functor for dynamic binding
	TEMPLATE_ARGS = FUNCTOR_TEMPLATE_ARGS
	FUNCTION_ARGS = FUNCTOR_FUNCTION_ARGS
	FUNCTION_PARA = FUNCTOR_FUNCTION_PARA
*/
template<typename ClassType, typename Ret FUNCTOR_TEMPLATE_ARGS >
class functor<Ret(FUNCTOR_FUNCTION_ARGS), dynamic_bind, ClassType>
{
private:
	struct FunctionHolderBase
	{
		virtual Ret operator()(FUNCTOR_FUNCTION_ARGS) const = 0;
		virtual ~FunctionHolderBase(){};
        virtual bool callable() const = 0;
	};


	template<typename ClassPointerType, typename Function>
	struct FunctionHolder : public FunctionHolderBase
	{
		ClassPointerType pObj_;
		Function func_;

		FunctionHolder(ClassPointerType pObj, const Function& func)
			: pObj_(pObj), func_(func){}

        bool callable() const
        {
            return bool(pObj_);
        }

		Ret operator()(FUNCTOR_FUNCTION_ARGS) const
		{
			return (pObj_->*func_)(FUNCTOR_FUNCTION_PARA);
		}
	};

	template<typename Function>
	struct FunctionHolder<ClassStub, Function> : public FunctionHolderBase
	{
		Function func_;

		FunctionHolder(Function func):func_(func){}

        bool callable() const
        {
            return bool(func_);
        }

		Ret operator()(FUNCTOR_FUNCTION_ARGS) const
		{
			return (func_)(FUNCTOR_FUNCTION_PARA);
		}
	};

	typedef acapella::shared_ptr<const FunctionHolderBase> FunctionHolderPtr;
	typedef FunctionHolderPtr HolderType;

public:
	typedef Ret(*FunctionType)(FUNCTOR_FUNCTION_ARGS);
	typedef functor<Ret(FUNCTOR_FUNCTION_ARGS), dynamic_bind, ClassType> functor_type;
	typedef functor_list<Ret(FUNCTOR_FUNCTION_ARGS), dynamic_bind, ClassType> functor_list_type;
	typedef Ret return_type;

	functor(){};

	~functor(){};

	functor(const functor& func)
	{
		m_hs = func.m_hs;
	} 

	functor(FunctionType func)
	{
		m_hs = FunctionHolderPtr(
			new FunctionHolder<ClassStub, FunctionType>(func));
	} 

	template <typename ClassPointerType, typename MemFun>
	functor(ClassPointerType pObj, MemFun mFun)
	{
		m_hs = FunctionHolderPtr(
			new FunctionHolder<ClassPointerType, MemFun>(pObj, mFun));
	}

	functor& operator=(const functor& functor_)
	{
		if (this == &functor_)
		{
			return *this;
		}
		m_hs = functor_.m_hs;
		return *this;
	}

	void clear()
	{
		m_hs = FunctionHolderPtr(0);
	}
	
	bool callable() const
	{
        if (m_hs == 0)
        {
            return false;
        }
		return m_hs->callable();
	}
	
	Ret operator()(FUNCTOR_FUNCTION_ARGS) const
	{
        ACAPELLA_ASSERT(callable(), "functor is not callable");
		return (*m_hs)(FUNCTOR_FUNCTION_PARA);
	}

private:

	HolderType  m_hs;
};


/*
	functor for static member function binding
	this should be faster than dynamic binding
	TEMPLATE_ARGS = FUNCTOR_TEMPLATE_ARGS
	FUNCTION_ARGS = FUNCTOR_FUNCTION_ARGS
	FUNCTION_PARA = FUNCTOR_FUNCTION_PARA
*/
template<typename ClassType, typename Ret FUNCTOR_TEMPLATE_ARGS >
class functor<Ret(FUNCTOR_FUNCTION_ARGS), static_bind, ClassType>
{
private:
	typedef Ret(ClassType::*MemberFunctionType)(FUNCTOR_FUNCTION_ARGS);
	typedef typename traits::type_traits<ClassType>::pointer_type ClassPoinerType;

public:
	typedef functor<Ret(FUNCTOR_FUNCTION_ARGS), static_bind, ClassType> functor_type;
	typedef functor_list<Ret(FUNCTOR_FUNCTION_ARGS), static_bind, ClassType> functor_list_type;
	typedef Ret return_type;

	functor():pObj_(0), func_(0){};
	~functor(){};

	functor(ClassPoinerType pObj, MemberFunctionType mFun)
		:pObj_(pObj), func_(mFun)
	{}

	functor(const functor& functor_)
		:pObj_(functor_.pObj_), func_(functor_.func_)
	{

	}

	functor& operator=(const functor& functor_)
	{
		if (this == &functor_)
		{
			return *this;
		}

		pObj_ = functor_.pObj_;
		func_ = functor_.func_;
		return *this;
	}


	void clear()
	{
		pObj_ = 0;
	}

	bool callable() const
	{
		return pObj_ != 0;
	}

	inline Ret operator()(FUNCTOR_FUNCTION_ARGS) const
	{
		ACAPELLA_ASSERT(callable(), "functor is not callable");
		return (pObj_->*func_)(FUNCTOR_FUNCTION_PARA);
	}

private:
	ClassPoinerType pObj_;
	MemberFunctionType func_;
};


/*
	functor for static function binding
	this should be faster than dynamic binding
	TEMPLATE_ARGS = FUNCTOR_TEMPLATE_ARGS
	FUNCTION_ARGS = FUNCTOR_FUNCTION_ARGS
	FUNCTION_PARA = FUNCTOR_FUNCTION_PARA
*/
template<typename Ret FUNCTOR_TEMPLATE_ARGS >
class functor<Ret(FUNCTOR_FUNCTION_ARGS), static_bind, ClassStub>
{
private:
	typedef Ret(*FunctionType)(FUNCTOR_FUNCTION_ARGS);

public:
	typedef functor<Ret(FUNCTOR_FUNCTION_ARGS), static_bind, ClassStub> functor_type;
	typedef functor_list<Ret(FUNCTOR_FUNCTION_ARGS), static_bind, ClassStub> functor_list_type;
	typedef Ret return_type;

	functor():func_(0){};
	~functor(){};

	functor(const functor& functor_)
		:func_(functor_.func_)
	{

	}

	functor(FunctionType mFun)
		:func_(mFun)
	{}

	functor& operator=(const functor& functor_)
	{
		if (this == &functor_)
		{
			return *this;
		}

		func_ = functor_.func_;
		return *this;
	}


	void clear()
	{
		func_ = 0;
	}

	bool callable() const
	{
		return func_ != 0;
	}

	inline Ret operator()(FUNCTOR_FUNCTION_ARGS) const
	{
		ACAPELLA_ASSERT(callable(), "functor is not callable");
		return (func_)(FUNCTOR_FUNCTION_PARA);
	}

private:
	FunctionType func_;
};



/*
	functor_list
	TEMPLATE_ARGS = FUNCTOR_TEMPLATE_ARGS
	FUNCTION_ARGS = FUNCTOR_FUNCTION_ARGS
	FUNCTION_PARA = FUNCTOR_FUNCTION_PARA
*/
template<typename BindType, typename ClassType, typename Ret FUNCTOR_TEMPLATE_ARGS >
class functor_list<Ret(FUNCTOR_FUNCTION_ARGS), BindType, ClassType>
{
public:
	typedef functor<Ret(FUNCTOR_FUNCTION_ARGS), BindType, ClassType> functor_type;
	typedef functor_list<Ret(FUNCTOR_FUNCTION_ARGS), BindType, ClassType> functor_list_type;
	typedef Ret return_type;
	   
	functor_list()
    {
    }

	~functor_list()
    {
    }
	   
	functor_list(const functor_list& del)
		:m_hs(del.m_hs)
	{
	}

	functor_list(const functor_type& del)
	{
		m_hs.push_back(del);
	}

	functor_list& operator+(const functor_list& rhs)
	{
		m_hs.insert(m_hs.end(), rhs.m_hs.begin(), rhs.m_hs.end());
		return *this;
	}

	functor_list& operator+(const functor_type& rhs)
	{
		m_hs.push_back(rhs);
		return *this;
	}

	functor_list& operator+=(const functor_list& rhs)
	{
		*this = *this + rhs;
		return *this;
	}

	functor_list& operator+=(const functor_type& rhs)
	{
		*this = *this + rhs;
		return *this;
	}

	_uint32_ size() const
	{
		return m_hs.size();
	}

	void clear()
	{
		m_hs.clear();
	}

	Ret operator()(FUNCTOR_FUNCTION_ARGS) const
	{
		for (HolderIterator it = m_hs.begin();
			it != m_hs.end() - 1;
			++it)
		{
			(*it)(FUNCTOR_FUNCTION_PARA);
		}
		return (*(m_hs.end() - 1))(FUNCTOR_FUNCTION_PARA);
	}


private:
	typedef std::vector<functor_type> HolderType;
	typedef typename HolderType::const_iterator  HolderIterator;

	HolderType  m_hs;
};


/*
	functor_type
	TEMPLATE_ARGS = FUNCTOR_TEMPLATE_ARGS
*/
template<typename BindType, typename RtVal, typename ClassType FUNCTOR_TEMPLATE_ARGS>
struct functor_type<RtVal (ClassType::*)(FUNCTOR_FUNCTION_ARGS), BindType>
{
	typedef functor<RtVal (FUNCTOR_FUNCTION_ARGS), BindType, ClassType> type;
	typedef functor_list<RtVal (FUNCTOR_FUNCTION_ARGS), BindType, ClassType> list_type;
};

template<typename BindType, typename RtVal FUNCTOR_TEMPLATE_ARGS>
struct functor_type<RtVal (*)(FUNCTOR_FUNCTION_ARGS), BindType>
{
	typedef functor<RtVal (FUNCTOR_FUNCTION_ARGS), BindType, ClassStub> type;
	typedef functor_list<RtVal (FUNCTOR_FUNCTION_ARGS), BindType, ClassStub> list_type;
};

/*********************************************************/





